home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’93
/
CountPatches
/
CountPatches.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-17
|
10KB
|
312 lines
#include <Types.h>
#include <Traps.h>
#include <SetupA4.h>
#include <Files.h>
#define _NSetTrapAddress 0xA247 /* from Think Reference; not defined in Traps.h */
/*******************************************************************************
Typedefs.
*******************************************************************************/
typedef pascal short (*HOpenResFileProc)(short vRefNum,
long dirID,
ConstStr255Param fn,
char permission);
typedef pascal void (*CloseResFileProc)(short refNum);
typedef pascal void (*NSetTrapAddressProc)(long trapAddr, short trapNum, short trapType);
typedef pascal void (*LaunchProc)(void);
/*******************************************************************************
Globals.
*******************************************************************************/
HOpenResFileProc gOldHOpenResFileAddress;
CloseResFileProc gOldCloseResFileAddress;
NSetTrapAddressProc gOldNSetTrapAddressAddress;
LaunchProc gOldLaunchAddress;
short gCounter;
Str255 gInitName;
/*******************************************************************************
Function prototypes. Each trap patched should have a new function with
the same parms as the original trap.
*******************************************************************************/
void main(void);
pascal void DrawIt(StringPtr theString);
StringPtr NumToPStr(short n); /* from NumToPStr.c */
StringPtr StrPCat(StringPtr a, StringPtr b); /* from NumToPStr.c */
/*** HOpenResFile ***/
pascal short MyHOpenResFile(short vRefNum,
long dirID,
ConstStr255Param fn,
char permission);
/*** CloseResFile ***/
pascal void MyCloseResFile(short refNum);
/*** NSetTrapAddress ***/
pascal void MyNSetTrapAddress(long trapAddr, short trapNum, short trapType);
/*** Launch ***/
pascal void MyLaunch(void);
/*******************************************************************************
main
When INITs are loaded, the operating system jumps to the first byte in the
resource to execute them. Under THINK C, the compiler adds a little
snippet of code at the beginning of the INIT that jumps to main(), which
means that main() can appear anywhere in the source. Under MPW, this isn’t
done for you, so you have to make sure that main() is the first procedure
in your source code.
In order for INITs to stay resident, they must be loaded into the System
heap. Because they contain executable instructions that can be called at
any time, the INIT resource should be locked. Since they’ll remain locked
during the entire time the computer is on, they should be loaded as low in
the heap as possible to prevent fragmentation. Setting the resSysHeap and
resLocked bits of our INIT resource will do this for us. However, none of
this prevents our INIT resource from being removed from memory as soon as
the file it’s in is closed. Therefore, the first thing our main() routine
does detach the INIT from the resource file.
Next, we plug ourselves into the HOpenResFile() routine. This is done in two
steps. First, we get the address of the current HOpenResFile() routine and save
it. Then we install the address of our own custom routine.
*******************************************************************************/
void main()
{
Ptr ourAddress;
RememberA0();
SetUpA4();
asm {
move.l A0, ourAddress ; A0 points to the beginning of the
; INIT, courtesy of the THINK glue
}
DetachResource(RecoverHandle(ourAddress));
gOldHOpenResFileAddress = (HOpenResFileProc) GetToolTrapAddress(_HOpenResFile);
SetToolTrapAddress((long) MyHOpenResFile, _HOpenResFile);
gOldCloseResFileAddress = (CloseResFileProc) GetToolTrapAddress(_CloseResFile);
SetToolTrapAddress((long) MyCloseResFile, _CloseResFile);
gOldNSetTrapAddressAddress = (NSetTrapAddressProc) GetOSTrapAddress(_NSetTrapAddress);
SetOSTrapAddress((long) MyNSetTrapAddress, _NSetTrapAddress);
gOldLaunchAddress = (LaunchProc) GetToolTrapAddress(_Launch);
SetToolTrapAddress((long) MyLaunch, _Launch);
RestoreA4();
}
/*******************************************************************************
MyHOpenResFile
This the patch that gets called whenever any application calls HOpenResFile.
We check if they are opening an INIT. If so, we want to do our thing.
Under the THINK environments, you are allowed to have global variables in
standalone code as long as you call SetUpA4() first. Since we’ve stored
the address of the original HOpenResFile routine in a global, the first we do
is call SetUpA4(). Then we call the original HOpenResFile so that it can do its
processing.
Next, it’s time for our custom code to step in.
*******************************************************************************/
pascal short MyHOpenResFile(short vRefNum,
long dirID,
ConstStr255Param fn,
char permission)
{
short result;
FInfo fndrInfo;
OSErr iErr;
SetUpA4();
gCounter = -1; /* -1 means don't track it */
iErr = HGetFInfo(vRefNum, dirID, fn, &fndrInfo);
if ( (iErr == noErr) &&
(fndrInfo.fdType == 'INIT') ||
(fndrInfo.fdType == 'cdev') ) {
gCounter = 0; /* clear our global counter */
BlockMove(fn, gInitName, *fn+1);
}
result = gOldHOpenResFileAddress(vRefNum, dirID, fn, permission);
RestoreA4();
return result;
}
/*******************************************************************************
MyCloseResFile
This the patch that gets called whenever any application calls CloseResFile.
We check if they are opening an INIT. If so, we want to do our thing.
Under the THINK environments, you are allowed to have global variables in
standalone code as long as you call SetUpA4() first. Since we’ve stored
the address of the original CloseResFile routine in a global, the first we do
is call SetUpA4(). Then we call the original CloseResFile so that it can do its
processing.
Next, it’s time for our custom code to step in.
*******************************************************************************/
pascal void MyCloseResFile(short refNum)
{
StringPtr numString;
SetUpA4();
if (gCounter != -1) {
numString = NumToPStr(gCounter);
numString = StrPCat(gInitName, NumToPStr(gCounter));
DrawIt(numString);
while (!Button()) {} ;
while (Button()) {};
}
gOldCloseResFileAddress(refNum);
RestoreA4();
}
/*******************************************************************************
MyNSetTrapAddress
This the patch that gets called whenever any application calls NSetTrapAddress.
We check if they are opening an INIT. If so, we want to do our thing.
Under the THINK environments, you are allowed to have global variables in
standalone code as long as you call SetUpA4() first. Since we’ve stored
the address of the original NSetTrapAddress routine in a global, the first we do
is call SetUpA4(). Then we call the original NSetTrapAddress so that it can do its
processing.
Next, it’s time for our custom code to step in.
*******************************************************************************/
pascal void MyNSetTrapAddress(long trapAddr, short trapNum, short trapType)
{
NSetTrapAddressProc nextLink;
short trapWord;
short callerTrapWord; // the trap word used to make this call is in d1
asm {
movem.l a0-a5/d0-d7,-(sp)
move.w d0,trapWord
move.w d1,callerTrapWord
}
SetUpA4();
nextLink = gOldNSetTrapAddressAddress;
if (gCounter != -1)
gCounter++;
asm{
move.l (sp)+,a4 ; same as RestoreA4()
movem.l (sp)+,a0-a5/d0-d7
move.l nextLink,a1
unlk a6
jmp (a1)
}
}
/*******************************************************************************
MyLaunch
This the patch that gets called whenever any application calls Launch.
Under the THINK environments, you are allowed to have global variables in
standalone code as long as you call SetUpA4() first. Since we’ve stored
the address of the original Launch routine in a global, the first we do
is call SetUpA4(). Then we call the original Launch so that it can do its
processing.
Next, it’s time for our custom code to step in.
*******************************************************************************/
pascal void MyLaunch()
{
LaunchProc nextLink;
asm {
movem.l a0-a5/d0-d7,-(sp)
}
SetUpA4();
nextLink = gOldLaunchAddress;
SetToolTrapAddress((long) gOldHOpenResFileAddress, _HOpenResFile);
SetToolTrapAddress((long) gOldCloseResFileAddress, _CloseResFile);
SetOSTrapAddress((long) gOldNSetTrapAddressAddress, _NSetTrapAddress);
SetToolTrapAddress((long) gOldLaunchAddress, _Launch);
asm{
move.l (sp)+,a4 ; same as RestoreA4()
movem.l (sp)+,a0-a5/d0-d7
move.l nextLink,a1
unlk a6
jmp (a1)
}
}
/*******************************************************************************
DrawIt
Initialize a QuickDraw
*******************************************************************************/
#include <QuickDraw.h>
typedef struct QuickDraw { /* struct to hold QuickDraw globals */
char private[76];
long randSeed;
BitMap screenBits;
Cursor arrow;
Pattern dkGray;
Pattern ltGray;
Pattern gray;
Pattern black;
Pattern white;
GrafPtr thePort;
} QuickDraw;
pascal void DrawIt(StringPtr theString)
{
GrafPort myPort; /* port we draw into */
QuickDraw qdGlobals; /* our own personal QD globals... */
Rect theRect = {145, 240, 165, 440};
SetUpA4();
InitGraf(&qdGlobals.thePort); /* initialize our qdGlobals structure */
OpenPort(&myPort);
SetPort(&myPort);
InitFonts();
MoveTo(240,160);
EraseRect(&theRect);
DrawString(theString);
RestoreA4();
}